package com.kxmall.framework.monitor;

import com.kxmall.common.enums.DeviceType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Token返回监控器
 * 专门监控登录成功返回Token的唯一性和安全性
 *
 * @author kxmall
 */
@Slf4j
@Component
public class TokenReturnMonitor {

    // 监控统计
    private final AtomicLong totalTokenReturned = new AtomicLong(0);
    private final AtomicLong appTokenReturned = new AtomicLong(0);
    private final AtomicLong riderTokenReturned = new AtomicLong(0);
    private final AtomicLong sysTokenReturned = new AtomicLong(0);
    private final AtomicLong tokenReturnFailures = new AtomicLong(0);
    private final AtomicLong tokenValidationFailures = new AtomicLong(0);

    // Token返回记录（用于监控和分析）
    private final ConcurrentHashMap<String, TokenReturnRecord> tokenReturnHistory = new ConcurrentHashMap<>();

    /**
     * 记录Token返回成功
     */
    public void recordTokenReturn(String tokenValue, String userType, DeviceType deviceType, Long userId) {
        try {
            // 更新统计
            totalTokenReturned.incrementAndGet();
            updateUserTypeReturnCount(userType, 1);

            // 记录Token返回信息
            TokenReturnRecord record = new TokenReturnRecord(
                tokenValue, userType, deviceType.getDevice(), userId, System.currentTimeMillis(), true
            );
            tokenReturnHistory.put(generateRecordKey(userType, userId, System.currentTimeMillis()), record);

            log.info("📤 Token返回成功监控 - 用户类型: {}, 设备: {}, 用户ID: {}, Token前缀: {}, 总返回数: {}", 
                userType, deviceType.getDevice(), userId,
                tokenValue.substring(0, Math.min(10, tokenValue.length())) + "...",
                totalTokenReturned.get());

        } catch (Exception e) {
            log.error("记录Token返回成功监控异常", e);
        }
    }

    /**
     * 记录Token返回失败
     */
    public void recordTokenReturnFailure(String reason, String userType, DeviceType deviceType, Long userId) {
        try {
            tokenReturnFailures.incrementAndGet();

            // 记录失败信息
            TokenReturnRecord record = new TokenReturnRecord(
                null, userType, deviceType.getDevice(), userId, System.currentTimeMillis(), false, reason
            );
            tokenReturnHistory.put(generateRecordKey(userType, userId, System.currentTimeMillis()), record);

            log.error("🚨 Token返回失败监控 - 原因: {}, 用户类型: {}, 设备: {}, 用户ID: {}, 累计失败: {}", 
                reason, userType, deviceType.getDevice(), userId, tokenReturnFailures.get());

        } catch (Exception e) {
            log.error("记录Token返回失败监控异常", e);
        }
    }

    /**
     * 记录Token验证失败
     */
    public void recordTokenValidationFailure(String validationType, String reason, String userType, Long userId) {
        try {
            tokenValidationFailures.incrementAndGet();

            log.warn("🚨 Token验证失败监控 - 验证类型: {}, 原因: {}, 用户类型: {}, 用户ID: {}, 累计验证失败: {}", 
                validationType, reason, userType, userId, tokenValidationFailures.get());

        } catch (Exception e) {
            log.error("记录Token验证失败监控异常", e);
        }
    }

    /**
     * 检查Token返回唯一性
     */
    public boolean checkTokenReturnUniqueness(String tokenValue, String userType, Long userId) {
        try {
            // 检查是否有重复的Token返回记录
            long currentTime = System.currentTimeMillis();
            long timeWindow = 5000; // 5秒时间窗口

            boolean hasDuplicate = tokenReturnHistory.values().stream()
                .anyMatch(record -> 
                    record.isSuccess() &&
                    tokenValue.equals(record.getTokenValue()) &&
                    userType.equals(record.getUserType()) &&
                    userId.equals(record.getUserId()) &&
                    (currentTime - record.getReturnTime()) < timeWindow
                );

            if (hasDuplicate) {
                log.warn("🚨 检测到重复Token返回 - Token前缀: {}, 用户: {}:{}", 
                    tokenValue.substring(0, Math.min(10, tokenValue.length())) + "...", userType, userId);
                return false;
            }

            return true;

        } catch (Exception e) {
            log.error("检查Token返回唯一性异常", e);
            return true; // 异常时假设唯一
        }
    }

    /**
     * 获取Token返回成功率
     */
    public double getTokenReturnSuccessRate() {
        long total = totalTokenReturned.get() + tokenReturnFailures.get();
        if (total == 0) {
            return 100.0;
        }
        return (double) totalTokenReturned.get() / total * 100.0;
    }

    /**
     * 获取Token返回统计信息
     */
    public String getTokenReturnStats() {
        return String.format(
            "Token返回统计 - 总成功: %d, APP: %d, 骑手: %d, 系统: %d, 失败: %d, 验证失败: %d, 成功率: %.2f%%",
            totalTokenReturned.get(), appTokenReturned.get(), riderTokenReturned.get(), sysTokenReturned.get(),
            tokenReturnFailures.get(), tokenValidationFailures.get(), getTokenReturnSuccessRate()
        );
    }

    /**
     * 获取详细统计信息
     */
    public TokenReturnStats getDetailedStats() {
        return new TokenReturnStats(
            totalTokenReturned.get(),
            appTokenReturned.get(),
            riderTokenReturned.get(),
            sysTokenReturned.get(),
            tokenReturnFailures.get(),
            tokenValidationFailures.get(),
            getTokenReturnSuccessRate(),
            tokenReturnHistory.size()
        );
    }

    /**
     * 清理过期Token返回记录
     */
    @Scheduled(fixedRate = 600000) // 10分钟执行一次
    public void cleanupExpiredReturnRecords() {
        try {
            long currentTime = System.currentTimeMillis();
            long expireTime = 3600000; // 1小时过期时间

            int beforeSize = tokenReturnHistory.size();

            tokenReturnHistory.entrySet().removeIf(entry -> {
                TokenReturnRecord record = entry.getValue();
                return (currentTime - record.getReturnTime()) > expireTime;
            });

            int afterSize = tokenReturnHistory.size();
            int cleanedCount = beforeSize - afterSize;

            if (cleanedCount > 0) {
                log.info("Token返回记录清理完成 - 清理数量: {}, 剩余记录: {}", cleanedCount, afterSize);
            }

        } catch (Exception e) {
            log.error("清理过期Token返回记录异常", e);
        }
    }

    /**
     * 重置统计信息
     */
    public void resetStats() {
        totalTokenReturned.set(0);
        appTokenReturned.set(0);
        riderTokenReturned.set(0);
        sysTokenReturned.set(0);
        tokenReturnFailures.set(0);
        tokenValidationFailures.set(0);
        tokenReturnHistory.clear();
        log.info("Token返回监控统计已重置");
    }

    /**
     * 检查是否存在问题
     */
    public boolean hasReturnIssues() {
        return tokenReturnFailures.get() > 10 || tokenValidationFailures.get() > 5 || getTokenReturnSuccessRate() < 95.0;
    }

    /**
     * 更新用户类型返回统计
     */
    private void updateUserTypeReturnCount(String userType, int delta) {
        switch (userType) {
            case "app_user":
                appTokenReturned.addAndGet(delta);
                break;
            case "rider_user":
                riderTokenReturned.addAndGet(delta);
                break;
            case "sys_user":
                sysTokenReturned.addAndGet(delta);
                break;
        }
    }

    /**
     * 生成记录键
     */
    private String generateRecordKey(String userType, Long userId, long timestamp) {
        return userType + ":" + userId + ":" + timestamp;
    }

    /**
     * Token返回记录类
     */
    public static class TokenReturnRecord {
        private final String tokenValue;
        private final String userType;
        private final String deviceType;
        private final Long userId;
        private final long returnTime;
        private final boolean success;
        private final String failureReason;

        public TokenReturnRecord(String tokenValue, String userType, String deviceType, Long userId, 
                               long returnTime, boolean success) {
            this(tokenValue, userType, deviceType, userId, returnTime, success, null);
        }

        public TokenReturnRecord(String tokenValue, String userType, String deviceType, Long userId, 
                               long returnTime, boolean success, String failureReason) {
            this.tokenValue = tokenValue;
            this.userType = userType;
            this.deviceType = deviceType;
            this.userId = userId;
            this.returnTime = returnTime;
            this.success = success;
            this.failureReason = failureReason;
        }

        // Getters
        public String getTokenValue() { return tokenValue; }
        public String getUserType() { return userType; }
        public String getDeviceType() { return deviceType; }
        public Long getUserId() { return userId; }
        public long getReturnTime() { return returnTime; }
        public boolean isSuccess() { return success; }
        public String getFailureReason() { return failureReason; }
    }

    /**
     * Token返回统计信息类
     */
    public static class TokenReturnStats {
        private final long totalReturned;
        private final long appTokens;
        private final long riderTokens;
        private final long sysTokens;
        private final long failures;
        private final long validationFailures;
        private final double successRate;
        private final int recordCount;

        public TokenReturnStats(long totalReturned, long appTokens, long riderTokens, long sysTokens, 
                              long failures, long validationFailures, double successRate, int recordCount) {
            this.totalReturned = totalReturned;
            this.appTokens = appTokens;
            this.riderTokens = riderTokens;
            this.sysTokens = sysTokens;
            this.failures = failures;
            this.validationFailures = validationFailures;
            this.successRate = successRate;
            this.recordCount = recordCount;
        }

        // Getters
        public long getTotalReturned() { return totalReturned; }
        public long getAppTokens() { return appTokens; }
        public long getRiderTokens() { return riderTokens; }
        public long getSysTokens() { return sysTokens; }
        public long getFailures() { return failures; }
        public long getValidationFailures() { return validationFailures; }
        public double getSuccessRate() { return successRate; }
        public int getRecordCount() { return recordCount; }
    }
}
